001    /* $RCSfile: CryptoTool.java,v $
002     * $Revision: 1.12 $
003     * $Date: 2002/11/23 11:07:03 $
004     * $Author: uwe_guenther $
005     * $State: Exp $
006     *
007     * Created on January 13, 2002 6:57 PM
008     *
009     * Copyright (C) 2001 Uwe Guenther <uwe@cscc.de>
010     *
011     * This file is part of the jhbci JCE-ServiceProvider. The jhbci JCE-
012     * ServiceProvider is a library, written in JavaTM, that should be 
013     * used in HBCI banking applications (clients and may be servers),
014     * to do cryptographic operations.
015     *
016     * The jhbci library is free software; you can redistribute it and/or
017     * modify it under the terms of the GNU Lesser General Public
018     * License as published by the Free Software Foundation; either
019     * version 2.1 of the License, or (at your option) any later version.
020     *
021     * The jhbci library is distributed in the hope that it will be useful,
022     * but WITHOUT ANY WARRANTY; without even the implied warranty of
023     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
024     * Lesser General Public License for more details.
025     *
026     * You should have received a copy of the GNU Lesser General Public
027     * License along with this library; if not, write to the Free Software
028     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
029     *
030     */
031    
032    package de.cscc.crypto.tools;
033    
034    import java.io.FileInputStream;
035    import java.io.FileOutputStream;
036    import java.io.IOException;
037    import java.io.InputStream;
038    import java.io.ObjectInputStream;
039    import java.io.ObjectOutputStream;
040    import java.io.OutputStream;
041    import java.io.PrintStream;
042    import java.io.PrintWriter;
043    import java.io.PushbackInputStream;
044    import java.math.BigInteger;
045    import java.security.KeyPair;
046    import java.security.KeyPairGenerator;
047    import java.security.MessageDigest;
048    import java.security.Security;
049    import java.security.Signature;
050    import java.security.interfaces.RSAPrivateCrtKey;
051    import java.security.interfaces.RSAPublicKey;
052    import java.util.Arrays;
053    import java.util.logging.Level;
054    
055    import javax.crypto.Cipher;
056    import javax.crypto.CipherInputStream;
057    import javax.crypto.CipherOutputStream;
058    import javax.crypto.KeyGenerator;
059    import javax.crypto.SecretKey;
060    import javax.crypto.SecretKeyFactory;
061    
062    import de.cscc.crypto.provider.JHBCI;
063    import de.cscc.crypto.provider.spec.DESOperationModeInitializationVectorSpec;
064    import de.cscc.crypto.provider.spec.DESede3KeySpec;
065    import de.cscc.crypto.util.BigIntegerUtil;
066    import de.cscc.crypto.util.LoggerUtil;
067    
068    /** 
069     * CryptoTool Class.
070     *
071     * @author  <a href=mailto:uwe@cscc.de>Uwe Günther</a>
072     *
073     * @version $Revision: 1.12 $
074     */
075    public final class CryptoTool {
076        
077        private String version = "0.0.6";
078        
079        private String command = null;
080        private int keysize = 1024;
081        private String keyFile = null;
082        private char[] password = null;
083        private String pubKeyFile = null;
084        private String showKeyFormat = "hex";
085        private String inFile = null;
086        private String outFile = null;
087        private String algorithm = "DES1Key";
088        private String sigFile = null;
089        private String digestFile = null;
090        private boolean debug = false;
091        private boolean verbose = false;
092        private String logLevel = "off";
093        
094        private String lineSeparator = System.getProperty("line.separator");
095        private String fileSeparator = System.getProperty("file.separator");
096        private String userHome = System.getProperty("user.home");    
097        
098        private boolean headerPrinted = false;
099        
100        /**
101         * Don't instanciate this Object out of this class.
102         */
103        private CryptoTool() {
104        }
105    
106        /**
107         * String representation of this class. Useful for debugging.
108         *
109         * @return the String representation of this class.
110         */
111        public String toString() {
112            StringBuffer sb = new StringBuffer();
113            sb.append("version: ");
114            sb.append(version);
115            sb.append(lineSeparator);
116            sb.append("command: ");
117            sb.append(command);
118            sb.append(lineSeparator);
119            sb.append("keysize: ");
120            sb.append(keysize);
121            sb.append(lineSeparator);
122            sb.append("keyFile: ");
123            sb.append(keyFile);
124            sb.append(lineSeparator);    
125            sb.append("password: ");
126            sb.append(password);
127            sb.append(lineSeparator);            
128            sb.append("pubKeyFile: ");
129            sb.append(pubKeyFile);
130            sb.append(lineSeparator);         
131            sb.append("showKeyFormat: ");
132            sb.append(showKeyFormat);
133            sb.append(lineSeparator);            
134            sb.append("inFile: ");
135            sb.append(inFile);
136            sb.append(lineSeparator);    
137            sb.append("outFile: ");
138            sb.append(outFile);
139            sb.append(lineSeparator);
140            sb.append("algorithm: ");
141            sb.append(algorithm);
142            sb.append(lineSeparator);        
143            sb.append("sigFile: ");
144            sb.append(sigFile);
145            sb.append(lineSeparator);
146            sb.append("digestFile: ");
147            sb.append(digestFile);
148            sb.append(lineSeparator);        
149            sb.append("debug: ");
150            sb.append(debug);
151            sb.append(lineSeparator);    
152            sb.append("verbose: ");
153            sb.append(verbose);
154            sb.append(lineSeparator);
155            sb.append("logLevel: ");
156            sb.append(logLevel);
157            sb.append(lineSeparator);        
158            
159            sb.append(lineSeparator);        
160            
161            sb.append("userHome: ");
162            sb.append(userHome);
163            sb.append(lineSeparator);        
164            
165            return sb.toString();
166        }
167        
168        /**
169         * The main method.
170         *
171         * @param args the argument String array.
172         */
173        public static void main (String[] args) {
174            CryptoTool ct = new CryptoTool();
175            ct.run(args, System.out);
176        }
177        
178        /**
179         * The object starter.
180         *
181         * @param args the argument String array.
182         * @param out the PrintStream where the output should be go out.
183         */
184        public void run(String[] args, PrintStream out) {
185            try {
186                parseArgs(args);
187                doCommands(out);
188                if(debug) {
189                    System.err.println(this);
190                }            
191            } catch (Exception e) {
192                header();
193                System.err.println("CryptoTool Error: " + e.getMessage());
194                System.err.println();
195                if (debug) {
196                    e.printStackTrace();
197                    System.err.println(this);
198                }
199                System.exit(1);
200            } finally {
201                System.err.println();
202                System.err.println("Thanks for using CryptoTool.");
203            }
204        }
205        
206        /**
207         * Parse command line arguments.
208         *
209         * @args the argument String array.
210         * @throws Exception if there is an invalid commandline option.
211         */
212        private void parseArgs(String[] args) throws Exception {
213    
214            int i=0;
215    
216            for (i=0; (i < args.length) && args[i].startsWith("-"); i++) {
217    
218                String flags = args[i];
219                
220                /*
221                 * command modes
222                 */
223                if (flags.equalsIgnoreCase("-genkey")) {
224                    command = "genkey";
225                } else if (flags.equalsIgnoreCase("-showkey")) {
226                    command = "showkey";
227                } else if (flags.equalsIgnoreCase("-export")) {
228                    command = "export";           
229                } else if (flags.equalsIgnoreCase("-showpub")) {
230                    command = "showpub";                
231                } else if (flags.equalsIgnoreCase("-encrypt")) {
232                    command = "encrypt";
233                } else if (flags.equalsIgnoreCase("-decrypt")) {
234                    command = "decrypt";
235                } else if (flags.equalsIgnoreCase("-sign")) {
236                    command = "sign";
237                } else if (flags.equalsIgnoreCase("-verify")) {
238                    command = "verify";
239                } else if (flags.equalsIgnoreCase("-digest")) {
240                    command = "digest";
241                } else if (flags.equalsIgnoreCase("-help")) {
242                    usage();
243                    return;                
244                } 
245    
246                /*
247                 * specifiers
248                 */
249                else if (flags.equalsIgnoreCase("-keysize")) {
250                    if (++i == args.length) usage();
251                    keysize = Integer.parseInt(args[i]);
252                } else if (flags.equalsIgnoreCase("-keyfile")) {
253                    if (++i == args.length) usage();
254                    keyFile = args[i];
255                } else if (flags.equalsIgnoreCase("-keypass")) {
256                    if (++i == args.length) usage();
257                    password = args[i].toCharArray();                
258                } else if (flags.equalsIgnoreCase("-pubkey")) {
259                    if (++i == args.length) usage();
260                    pubKeyFile = args[i];                
261                } else if (flags.equalsIgnoreCase("-in")) {
262                    if (++i == args.length) usage();
263                    inFile = args[i];
264                } else if (flags.equalsIgnoreCase("-out")) {
265                    if (++i == args.length) usage();
266                    outFile = args[i];
267                } else if (flags.equalsIgnoreCase("-alg")) {
268                    if (++i == args.length) usage();
269                    algorithm = args[i];                
270                } else if (flags.equalsIgnoreCase("-sigfile")) {
271                    if (++i == args.length) usage();
272                    sigFile = args[i];
273                } else if (flags.equalsIgnoreCase("-digestfile")) {
274                    if (++i == args.length) usage();
275                    digestFile = args[i];
276                } else if (flags.equalsIgnoreCase("-logging")) {
277                    if (++i == args.length) usage();
278                    logLevel = args[i];
279                }
280    
281                /*
282                 * options
283                 */
284                else if (flags.equalsIgnoreCase("-v")) {
285                    verbose = true;
286                } else if (flags.equalsIgnoreCase("-debug")) {
287                    debug = true;
288                } else if (flags.equalsIgnoreCase("-hex")) {
289                    showKeyFormat = "hex";
290                } else if (flags.equalsIgnoreCase("-dec")) {
291                    showKeyFormat = "dec";
292                } else  {
293                    throw new Exception("Illegal option " + flags + ".");
294                }
295            }
296    
297            if (i<args.length || command==null) { 
298                usage();
299            }
300        }
301        
302        
303        /**
304         * Execute the commands.
305         *
306         * @out the PrintStream where the output should be go out.
307         * @throws Exception if some of the underlying commands goes wrong.
308         */    
309        private void doCommands(PrintStream out) throws Exception {
310            
311            if (command == null) {
312                return;
313            }
314            
315            //Add JHBCI Provider
316            Security.addProvider(new JHBCI());
317    
318            setStderrLogLevel();
319            
320            if (command.equals("genkey")) {
321                genKey();
322            } else if (command.equals("showkey")) {
323                showKey(out);
324            } else if (command.equals("export")) {
325                export();
326            } else if (command.equals("showpub")) {
327                showPub(out);            
328            } else if (command.equals("encrypt")) {
329                encrypt();
330            } else if (command.equals("decrypt")) {
331                decrypt();
332            } else if (command.equals("sign")) {
333                sign();
334            } else if (command.equals("verify")) {
335                verify();
336            } else if (command.equals("digest")) {
337                digest();  
338            }
339        }
340        
341        /**
342         * Sets a requested log level to the stderr.
343         *
344         * @throws Exception if a wrong log level has been requested.
345         */
346        private void setStderrLogLevel() throws Exception {
347            if (logLevel.equalsIgnoreCase("off")) { 
348                LoggerUtil.setConsoleLogging("", Level.OFF);        
349            } else if (logLevel.equalsIgnoreCase("severe")) { 
350                LoggerUtil.setConsoleLogging("", Level.SEVERE);
351            } else if (logLevel.equalsIgnoreCase("warning")) { 
352                LoggerUtil.setConsoleLogging("", Level.WARNING);
353            } else if (logLevel.equalsIgnoreCase("info")) { 
354                LoggerUtil.setConsoleLogging("", Level.INFO);
355            } else if (logLevel.equalsIgnoreCase("config")) { 
356                LoggerUtil.setConsoleLogging("", Level.CONFIG);
357            } else if (logLevel.equalsIgnoreCase("fine")) { 
358                LoggerUtil.setConsoleLogging("", Level.FINE);
359            } else if (logLevel.equalsIgnoreCase("finer")) { 
360                LoggerUtil.setConsoleLogging("", Level.FINER);
361            } else if (logLevel.equalsIgnoreCase("finest")) { 
362                LoggerUtil.setConsoleLogging("", Level.FINEST);
363            } else if(logLevel.equalsIgnoreCase("all")) { 
364                LoggerUtil.setConsoleLogging("", Level.ALL);
365            } else {
366                throw new Exception("Wrong logging level.");
367            }
368          
369        }
370        
371        /**
372         * Generate a RSA KeyPair and writes it to a DESede3Key encrypted
373         * "keyFile".
374         *
375         * @throws Exception if somthing goes wrong.
376         */
377        private void genKey() throws Exception {
378            if (keyFile == null) {
379                keyFile = userHome + fileSeparator + ".keyfile";
380            }
381            
382            header();
383            System.err.println("RSA Key File: " + keyFile);
384            System.err.println("RSA Key Length: " + keysize);
385            System.err.println();
386            
387            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "JHBCI");
388            keyGen.initialize(keysize);
389            KeyPair keyPair = keyGen.generateKeyPair();
390            
391            SecretKey desede3Key = null;
392     
393            if (password == null) {
394                System.err.print("Enter keyfile password: ");
395                password = readPasswd(System.in);
396                if (password.length < 6) {
397                    throw new Exception("New password must be at least 6 characters.");
398                }
399            
400            
401                System.err.print("Enter keyfile password again: ");
402                char[] password2 = readPasswd(System.in);
403                if (Arrays.equals(password, password2)) {
404                        desede3Key = genDESede3Key(password);
405                } else {
406                    throw new Exception("Too many failures - try later.");
407                }
408                System.err.println();
409            } else {
410                if (password.length < 6) {
411                    throw new Exception("New password must be at least 6 characters.");
412                }            
413                desede3Key = genDESede3Key(password);
414            }
415    
416            byte[] rawIV = {
417                (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
418                (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
419            };
420            
421            DESOperationModeInitializationVectorSpec iv = 
422            new DESOperationModeInitializationVectorSpec(rawIV); 
423            
424            Cipher encrypt = Cipher.getInstance(
425            "DESede3Key/CBC/ISO10126OctetPadding", "JHBCI");
426            encrypt.init(Cipher.ENCRYPT_MODE, desede3Key, iv);
427            
428            OutputStream fos = null;
429            OutputStream cos = null;
430            ObjectOutputStream oos = null;
431            try {
432                fos = new FileOutputStream(keyFile);
433                cos = new CipherOutputStream(fos, encrypt);
434                oos = new ObjectOutputStream(cos);
435                
436                oos.writeObject(keyPair.getPublic());
437                oos.flush();
438                oos.writeObject(keyPair.getPrivate());
439                oos.flush();
440             } finally {
441                if (oos != null) {
442                    oos.close();
443                } else if (cos != null) {
444                    cos.close();
445                } else if (fos != null) {
446                    fos.close();
447                }
448            }
449            System.err.println("Key successfully generated.");
450        }
451        
452        /**
453         * Generates a DESede3Key from a given password.
454         *
455         * @param password the password that will be used for this PBE algorithm.
456         * @return the generated SecretKey.
457         * @throws Exception if something goes wrong with the SecretKeyFactory.
458         */
459        private SecretKey genDESede3Key(char[] password) throws Exception {
460            MessageDigest innerDigest = 
461            MessageDigest.getInstance("RIPEMD160", "JHBCI");
462            MessageDigest outerDigest = 
463            MessageDigest.getInstance("RIPEMD160", "JHBCI");
464            
465            char [] salt = {
466                'D', 'o', 'n', 't', ' ', 'h', 'a', 'r', 'm', ' ', 'm', 'e', '.'
467            };
468            
469            int iterationCount = 5;
470    
471            for (int i = 0; i < iterationCount; i++) {
472                for (int j = 0; j < password.length; j++) {
473                    innerDigest.update((byte) ((password[j] >>> 8) & 0xff));
474                    innerDigest.update((byte) (password[j] & 0xff));
475                }
476                for (int j = 0; j < salt.length; j++) {
477                    innerDigest.update((byte) ((salt[j] >>> 8) & 0xff));
478                    innerDigest.update((byte) (salt[j] & 0xff));
479                }
480                MessageDigest tempDigest = (MessageDigest) innerDigest.clone();
481                outerDigest.update(innerDigest.digest());
482                innerDigest = tempDigest;
483            }
484            
485            byte[] firstDigest = outerDigest.digest();
486            
487            innerDigest.reset();
488            outerDigest.reset();
489            iterationCount = 15;
490            for (int i = 0; i < iterationCount; i++) {
491                for (int j = 0; j < password.length; j++) {
492                    innerDigest.update((byte) ((password[j] >>> 8) & 0xff));
493                    innerDigest.update((byte) (password[j] & 0xff));
494                }
495                for (int j = 0; j < salt.length; j++) {
496                    innerDigest.update((byte) ((salt[j] >>> 8) & 0xff));
497                    innerDigest.update((byte) (salt[j] & 0xff));
498                }
499                MessageDigest tempDigest = (MessageDigest) innerDigest.clone();
500                outerDigest.update(innerDigest.digest());
501                innerDigest = tempDigest;
502            }        
503            
504            byte[] secondDigest = outerDigest.digest();
505           
506            byte[] rawDESede3Key = new byte[24];
507            System.arraycopy(firstDigest, 0, rawDESede3Key, 0, 12);
508            System.arraycopy(secondDigest, 8, rawDESede3Key, 12, 12);
509            
510            DESede3KeySpec keySpec = new DESede3KeySpec(rawDESede3Key);
511            SecretKeyFactory factory = 
512            SecretKeyFactory.getInstance("DESede3Key", "JHBCI");
513            return factory.generateSecret(keySpec);
514        }
515        
516        /**
517         * Reads user password from given input stream.
518         *
519         * @param in the InputStream frow which the password will be read.
520         * @return the password.
521         * @throws IOException if somthing goeas wrong with the InputStream.
522         */
523        private char[] readPasswd(InputStream in) throws IOException {
524            char[] lineBuffer;
525            char[] buf;
526    
527            buf = lineBuffer = new char[128];
528    
529            int room = buf.length;
530            int offset = 0;
531            int c;
532            
533            loop:        
534            while (true) {
535                switch (c = in.read()) {
536                  case -1: 
537                  case '\n':
538                    break loop;
539    
540                  case '\r':
541                    int c2 = in.read();
542                    if ((c2 != '\n') && (c2 != -1)) {
543                        if (!(in instanceof PushbackInputStream)) {
544                            in = new PushbackInputStream(in);
545                        }
546                        ((PushbackInputStream)in).unread(c2);
547                    } else 
548                        break loop;
549    
550                  default:
551                    if (--room < 0) {
552                        buf = new char[offset + 128];
553                        room = buf.length - offset - 1;
554                        System.arraycopy(lineBuffer, 0, buf, 0, offset);
555                        Arrays.fill(lineBuffer, ' ');
556                        lineBuffer = buf;
557                    }
558                    buf[offset++] = (char) c;
559                    break;
560                }
561            }
562    
563            if (offset == 0) {
564                return null;
565            }
566    
567            char[] ret = new char[offset];
568            System.arraycopy(buf, 0, ret, 0, offset);
569            Arrays.fill(buf, ' ');
570    
571            return ret;
572        }    
573        
574        /**
575         * List the key bytes as hex.
576         *
577         * @param out the PrintStream where the key will be shown.
578         * @throws Exception if the password cna't be read from readKeyPair()
579         */
580        private void showKey(PrintStream out) throws Exception {
581            header();
582            KeyPair keyPair = readKeyPair();
583            System.err.println();        
584            
585            if (showKeyFormat.equals("dec")) {
586                out.print(toDecString((RSAPrivateCrtKey) keyPair.getPrivate()));
587            } else if (showKeyFormat.equals("hex")) {
588                out.print(toHexString((RSAPrivateCrtKey) keyPair.getPrivate()));
589            }
590        }
591        
592        /**
593         * Reads a KeyPair form a "keyFile".
594         *
595         * @throws Exception if something goes wrong.
596         */
597        private KeyPair readKeyPair() throws Exception {
598            if (keyFile == null) {
599                keyFile = userHome + fileSeparator + ".keyfile";
600            }
601            if (password == null) {
602                System.err.print("Enter keyfile password: ");
603                password = readPasswd(System.in);
604                System.err.println();
605            }
606            SecretKey desede3Key = genDESede3Key(password);
607            
608            byte[] rawIV = {
609                (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
610                (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
611            };
612            
613            DESOperationModeInitializationVectorSpec iv = 
614            new DESOperationModeInitializationVectorSpec(rawIV);        
615            
616            Cipher decrypt = Cipher.getInstance(
617            "DESede3Key/CBC/ISO10126OctetPadding", "JHBCI");
618            decrypt.init(Cipher.DECRYPT_MODE, desede3Key, iv);
619    
620            RSAPublicKey publicKey = null;
621            RSAPrivateCrtKey privateCrtKey = null;
622            InputStream fis = null;
623            InputStream cis = null;
624            ObjectInputStream ois = null;        
625            try {
626                fis = new FileInputStream(keyFile);
627                cis = new CipherInputStream(fis, decrypt);
628                ois = new ObjectInputStream(cis);
629                publicKey = (RSAPublicKey) ois.readObject(); 
630                privateCrtKey = (RSAPrivateCrtKey) ois.readObject();            
631            } finally {
632                if (ois != null) {
633                    ois.close();
634                } else if (cis != null) {
635                    cis.close();
636                } else if (fis != null) {
637                    fis.close();
638                }
639            }
640    
641            System.err.println("RSA Key File: " + keyFile);
642            System.err.print("RSA Key Length: "); 
643            System.err.print(privateCrtKey.getModulus().bitLength() + " bit");
644            System.err.println();
645            
646            return new KeyPair(publicKey, privateCrtKey);
647        }
648        
649        /**
650         * Converts a RSAPrivateCrtKey in its decimal String representation.
651         *
652         * @param key that will be converted to a String.
653         * @return the converted key as String.
654         */
655        private String toDecString(RSAPrivateCrtKey key) {
656            BigInteger modulus = key.getModulus();
657            BigInteger publicExponent = key.getPublicExponent();
658            BigInteger privateExponent = key.getPrivateExponent();
659            BigInteger primeP = key.getPrimeP();
660            BigInteger primeQ = key.getPrimeQ();
661            BigInteger primeExponentP = key.getPrimeExponentP();
662            BigInteger primeExponentQ = key.getPrimeExponentQ();
663            BigInteger crtCoefficient = key.getCrtCoefficient();
664            
665            StringBuffer sb = new StringBuffer();
666            sb.append("Key length: ");
667            sb.append(key.getModulus().bitLength());
668            sb.append(lineSeparator);
669            sb.append(lineSeparator);
670            
671            sb.append("Modulus: ");
672            sb.append(lineSeparator);
673            sb.append(toDec(modulus));
674            sb.append(lineSeparator);
675            sb.append(lineSeparator);
676            
677            sb.append("Public Exponent: ");
678            sb.append(lineSeparator);
679            sb.append(toDec(publicExponent));
680            sb.append(lineSeparator);
681            sb.append(lineSeparator);
682            
683            sb.append("Private Exponent: ");
684            sb.append(lineSeparator);
685            sb.append(toDec(privateExponent));
686            sb.append(lineSeparator);
687            sb.append(lineSeparator); 
688            
689            sb.append("Prime P: ");
690            sb.append(lineSeparator);
691            sb.append(toDec(primeP));
692            sb.append(lineSeparator);
693            sb.append(lineSeparator);        
694            
695            sb.append("Prime Q: ");
696            sb.append(lineSeparator);
697            sb.append(toDec(primeQ));
698            sb.append(lineSeparator);
699            sb.append(lineSeparator);
700            
701            sb.append("Prime Exponent P: ");
702            sb.append(lineSeparator);
703            sb.append(toDec(primeExponentP));
704            sb.append(lineSeparator);
705            sb.append(lineSeparator);        
706            
707            sb.append("Prime Exponent Q: ");
708            sb.append(lineSeparator);
709            sb.append(toDec(primeExponentQ));
710            sb.append(lineSeparator);
711            sb.append(lineSeparator);
712            
713            sb.append("Chinese Remainder Coefficient: ");
714            sb.append(lineSeparator);
715            sb.append(toDec(crtCoefficient));
716            sb.append(lineSeparator);                 
717            
718            return sb.toString();        
719        }
720        
721        /**
722         * Converts a BigInteger to decimal block string.
723         *
724         * @param number that will be converted to a String.
725         * @return the converted number as String.
726         */
727        private String toDec(BigInteger number) {
728            char[] block = number.toString().toCharArray();
729            StringBuffer sb = new StringBuffer();
730            int len = block.length;
731            for (int i = 0; i < len; i++) {    
732                 if ((i % 48 == 0) && (i != 0)) {
733                     sb.append(lineSeparator);
734                 } 
735                 sb.append(block[i]);
736            } 
737            return sb.toString();
738        }      
739        
740        /**
741         * Converts a RSAPrivateCrtKey in its hexadecimal String representation.
742         *
743         * @param key that will be converted to a String.
744         * @return the converted key as String.
745         */    
746        private String toHexString(RSAPrivateCrtKey key) {
747            BigInteger modulus = key.getModulus();
748            BigInteger publicExponent = key.getPublicExponent();
749            BigInteger privateExponent = key.getPrivateExponent();
750            BigInteger primeP = key.getPrimeP();
751            BigInteger primeQ = key.getPrimeQ();
752            BigInteger primeExponentP = key.getPrimeExponentP();
753            BigInteger primeExponentQ = key.getPrimeExponentQ();
754            BigInteger crtCoefficient = key.getCrtCoefficient();
755            
756            StringBuffer sb = new StringBuffer();
757            sb.append("Key length: ");
758            sb.append(key.getModulus().bitLength());
759            sb.append(lineSeparator);
760            sb.append(lineSeparator);
761            
762            sb.append("Modulus: ");
763            sb.append(lineSeparator);
764            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(modulus)));
765            sb.append(lineSeparator);
766            sb.append(lineSeparator);
767            
768            sb.append("Public Exponent: ");
769            sb.append(lineSeparator);
770            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(publicExponent)));
771            sb.append(lineSeparator);
772            sb.append(lineSeparator);
773            
774            sb.append("Private Exponent: ");
775            sb.append(lineSeparator);
776            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(privateExponent)));
777            sb.append(lineSeparator);
778            sb.append(lineSeparator); 
779            
780            sb.append("Prime P: ");
781            sb.append(lineSeparator);
782            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeP)));
783            sb.append(lineSeparator);
784            sb.append(lineSeparator);        
785            
786            sb.append("Prime Q: ");
787            sb.append(lineSeparator);
788            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeQ)));
789            sb.append(lineSeparator);
790            sb.append(lineSeparator);
791            
792            sb.append("Prime Exponent P: ");
793            sb.append(lineSeparator);
794            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeExponentP)));
795            sb.append(lineSeparator);
796            sb.append(lineSeparator);        
797            
798            sb.append("Prime Exponent Q: ");
799            sb.append(lineSeparator);
800            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(primeExponentQ)));
801            sb.append(lineSeparator);
802            sb.append(lineSeparator);
803            
804            sb.append("Chinese Remainder Coefficient: ");
805            sb.append(lineSeparator);
806            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(crtCoefficient)));
807            sb.append(lineSeparator);
808            
809            return sb.toString();
810        }
811    
812        /**
813         * Converts a byte array to hex string
814         *
815         * @param number that will be converted to a String.
816         * @return the converted number as String.
817         */
818        private String toHex(byte[] block) {
819            StringBuffer sb = new StringBuffer();
820            int len = block.length;
821            for (int i = 0; i < len; i++) {    
822                 if ((i % 16 == 0) && (i != 0)) {
823                     sb.append(lineSeparator);
824                 } 
825                 if (i % 16 != 0){
826                    sb.append(' ');
827                    if (i % 8 == 0) {
828                        sb.append(' ');
829                    }
830                 }
831                 byte2hex(block[i], sb);             
832            } 
833            return sb.toString();
834        }  
835        
836        
837        /**
838         * Converts a byte to hex digit and writes to the supplied buffer
839         *
840         * @param b the byte that should be converted into the buf.
841         * @param buf the StringBuffer.
842         */
843        private void byte2hex(byte b, StringBuffer buf) {
844            char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
845                                '9', 'a', 'b', 'c', 'd', 'e', 'f' };
846            int high = ((b & 0xf0) >> 4);
847            int low = (b & 0x0f);
848            buf.append(hexChars[high]);
849            buf.append(hexChars[low]);
850        }   
851            
852        /**
853         * Exports a public Key out of the "keyFile" into the "pubKeyFile".
854         *
855         * @throws Exception if something goes wrong.
856         */
857        private void export() throws Exception {
858            if (pubKeyFile == null) {
859                throw new Exception("You have to specify a PublicKeyOutputFile.");
860            }
861            header();
862            RSAPublicKey publicKey = (RSAPublicKey) readKeyPair().getPublic();
863            System.err.println("RSA Public Key File: " + pubKeyFile);
864            
865            OutputStream fos = null;
866            ObjectOutputStream oos = null;
867            try {
868                fos = new FileOutputStream(pubKeyFile);
869                oos = new ObjectOutputStream(fos);
870                oos.writeObject(publicKey);
871            } finally {
872                if (oos != null) {
873                    oos.close();
874                } else if (fos != null) {
875                    fos.close();
876                }
877            }
878            System.err.println();
879            System.err.println("Public Key successfully exported.");
880        }
881        
882        /**
883         * Shows a previously exported public Key which is read from "pubKeyFile".
884         *
885         * @param out the PrintStream to which the public Key will be printed out.
886         * @throws Exception if key reading goes wrong.
887         */
888        private void showPub(PrintStream out) throws Exception {
889            if (pubKeyFile == null) {
890                throw new Exception("You have to specify a PublicKeyInputFile.");
891            }        
892            header();
893            
894            RSAPublicKey publicKey = readPublicKey();
895            System.err.println();
896            
897            if (showKeyFormat.equals("dec")) {
898                out.print(toDecString(publicKey));
899            } else if (showKeyFormat.equals("hex")) {
900                out.print(toHexString(publicKey));
901            }
902        }
903        
904        
905        /**
906         * Reads a previously exported public Key from "pubKeyFile".
907         *
908         * @throws Exception if key reading goes wrong.
909         */    
910        private RSAPublicKey readPublicKey() throws Exception {
911            if (pubKeyFile == null) {
912                throw new Exception("You have to specify a PublicKeyInputFile.");
913            }    
914            System.err.println("RSA Public Key File: " + pubKeyFile);     
915            
916            RSAPublicKey publicKey = null;
917            InputStream fis = null;
918            ObjectInputStream ois = null;
919            try {
920                fis = new FileInputStream(pubKeyFile);
921                ois = new ObjectInputStream(fis);            
922            
923                publicKey = (RSAPublicKey) ois.readObject(); 
924            } finally {
925                if (ois != null) {
926                    ois.close();
927                } else if (fis != null) {
928                    fis.close();
929                }
930            }
931            
932            System.err.print("RSA Key Length: "); 
933            System.err.print(publicKey.getModulus().bitLength() + " bit");
934            System.err.println();
935            
936            return publicKey;        
937        }
938        
939        /**
940         * Converts a RSAPublicKey in its decimal String representation.
941         *
942         * @param key that will be converted to a String.
943         * @return the converted key as String.
944         */
945        private String toDecString(RSAPublicKey key) {
946            BigInteger modulus = key.getModulus();
947            BigInteger publicExponent = key.getPublicExponent();
948            
949            StringBuffer sb = new StringBuffer();
950            sb.append("Key length: ");
951            sb.append(key.getModulus().bitLength());
952            sb.append(lineSeparator);
953            sb.append(lineSeparator);
954            
955            sb.append("Modulus: ");
956            sb.append(lineSeparator);
957            sb.append(toDec(modulus));
958            sb.append(lineSeparator);
959            sb.append(lineSeparator);
960            
961            sb.append("Public Exponent: ");
962            sb.append(lineSeparator);
963            sb.append(toDec(publicExponent));
964            sb.append(lineSeparator);
965            
966            return sb.toString();        
967        }    
968        
969        /**
970         * Converts a RSAPublicKey in its hexadecimal String representation.
971         *
972         * @param key that will be converted to a String.
973         * @return the converted key as String.
974         */    
975        private String toHexString(RSAPublicKey key) {
976            BigInteger modulus = key.getModulus();
977            BigInteger publicExponent = key.getPublicExponent();
978            
979            StringBuffer sb = new StringBuffer();
980            sb.append("Key length: ");
981            sb.append(key.getModulus().bitLength());
982            sb.append(lineSeparator);
983            sb.append(lineSeparator);
984            
985            sb.append("Modulus: ");
986            sb.append(lineSeparator);
987            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(modulus)));
988            sb.append(lineSeparator);
989            sb.append(lineSeparator);
990            
991            sb.append("Public Exponent: ");
992            sb.append(lineSeparator);
993            sb.append(toHex(BigIntegerUtil.toUnsignedByteArray(publicExponent)));
994            sb.append(lineSeparator);
995            
996            return sb.toString();
997        }    
998        
999        /**
1000         * Encrypts the "inFile" to the "outFile" with the "pubKeyFile".
1001         *
1002         * @throws Exception if something goes wrong.
1003         */    
1004        private void encrypt() throws Exception {
1005            if (inFile == null) {
1006                throw new Exception("You have to specify a PlainTextInputFile.");
1007            }
1008            if (outFile == null) {
1009                throw new Exception("You have to specify a CipherTextOutputFile.");
1010            }        
1011            
1012            header();
1013            System.err.println("Plain Text File: " + inFile);
1014            System.err.println("Cipher Text File: " + outFile);
1015    
1016            RSAPublicKey publicKey = readPublicKey();
1017            
1018            KeyGenerator keyGen = KeyGenerator.getInstance(algorithm, "JHBCI");
1019            SecretKey desKey = keyGen.generateKey();
1020            
1021            System.err.println("DES Key Wrapper File: " + outFile + ".des");
1022            System.err.print("DES Key Length: ");
1023            System.err.print(desKey.getEncoded().length * 7);
1024            System.err.println(" bit without parity");
1025            System.err.println();
1026    
1027            
1028            Cipher wrapper = Cipher.getInstance("RSA", "JHBCI");
1029            wrapper.init(Cipher.WRAP_MODE, publicKey);
1030            byte[] wrappedKey = wrapper.wrap(desKey);
1031            
1032            OutputStream kfos = new FileOutputStream(outFile + ".des");
1033            ObjectOutputStream oos = new ObjectOutputStream(kfos);
1034            oos.writeObject(algorithm);
1035            oos.writeObject(wrappedKey);
1036            kfos.close();
1037            
1038            Cipher encrypt = Cipher.getInstance(
1039            algorithm + "/CBC/ISO10126OctetPadding", "JHBCI");
1040            
1041            byte[] rawIV = {
1042                (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
1043                (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
1044            };
1045            
1046            DESOperationModeInitializationVectorSpec iv = 
1047            new DESOperationModeInitializationVectorSpec(rawIV);
1048            
1049            encrypt.init(Cipher.ENCRYPT_MODE, desKey, iv);
1050    
1051    
1052            InputStream fin = null;
1053            OutputStream fos = null;
1054            OutputStream cos = null;
1055            long before = System.currentTimeMillis();
1056            try {
1057                fin = new FileInputStream(inFile);
1058                fos = new FileOutputStream(outFile);
1059                cos = new CipherOutputStream(fos, encrypt);
1060                byte[] buffer = new byte[4096];
1061                loop:
1062                for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1063                    read = fin.read(buffer);
1064                    if (read == -1) {
1065                        if (k != 1) {
1066                            System.err.print('.');
1067                            for (int l = 0; l < (60 - k); l++) {
1068                                System.err.print(' ');
1069                            }
1070                        }
1071                        System.err.println("[" + i + "]");
1072                        System.err.println();
1073                        break loop;
1074                    }
1075                    cos.write(buffer, 0, (int) read);
1076                    i += read; 
1077                    if (i > j) {
1078                        if (k == 60) {
1079                            System.err.println('.' + "[" + i  + "]");
1080                            k = 1;
1081                        } else {
1082                            System.err.print('.');
1083                            k++;
1084                        }
1085                        j += 1024 * 100;
1086                    }
1087                }
1088            } finally {
1089                if (fin != null) {
1090                    try {
1091                        fin.close();
1092                    } finally {
1093                        if (fos != null) {
1094                            if (cos != null) {
1095                                cos.close();
1096                            } else {
1097                                fos.close();
1098                            }
1099                        }
1100                    }
1101                }
1102            }
1103            long after = System.currentTimeMillis();
1104            System.err.print("Time to encrypt the whole file: ");
1105            System.err.println((after - before) + "ms");
1106            
1107        }
1108        
1109        /**
1110         * Decrypts the "inFile" to the "outFile" with the "keyFile".
1111         *
1112         * @throws Exception if something goes wrong.
1113         */    
1114        private void decrypt() throws Exception {
1115            if (inFile == null) {
1116                throw new Exception("You have to specify a PlainTextInputFile.");
1117            }
1118            if (outFile == null) {
1119                throw new Exception("You have to specify a CipherTextOutputFile.");
1120            }        
1121            
1122            header();
1123            System.err.println("Cipher Text File: " + inFile);
1124            System.err.println("Plain Text File: " + outFile);
1125            System.err.println();
1126            
1127            InputStream kfis = new FileInputStream(inFile + ".des");
1128            ObjectInputStream ois = new ObjectInputStream(kfis);
1129            
1130            algorithm = (String) ois.readObject();
1131            byte[] wrappedKey = (byte[]) ois.readObject();
1132            ois.close();
1133            
1134            RSAPrivateCrtKey privateCrtKey = 
1135            (RSAPrivateCrtKey) readKeyPair().getPrivate();     
1136            Cipher unwrapper = Cipher.getInstance("RSA", "JHBCI");
1137            unwrapper.init(Cipher.UNWRAP_MODE, privateCrtKey);
1138            SecretKey desKey = 
1139            (SecretKey) unwrapper.unwrap(wrappedKey, algorithm, Cipher.SECRET_KEY); 
1140    
1141            System.err.println("DES Key Wrapper File: " + inFile + ".des");
1142            System.err.print("DES Key Length: ");
1143            System.err.print(desKey.getEncoded().length * 7);
1144            System.err.println(" bit without parity");
1145            System.err.println();        
1146            
1147            Cipher decrypt = Cipher.getInstance(
1148            algorithm + "/CBC/ISO10126OctetPadding", "JHBCI");
1149            
1150            byte[] rawIV = {
1151                (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
1152                (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef
1153            };
1154            
1155            DESOperationModeInitializationVectorSpec iv = 
1156            new DESOperationModeInitializationVectorSpec(rawIV);
1157            
1158            decrypt.init(Cipher.DECRYPT_MODE, desKey, iv);
1159            
1160            InputStream fis = null;
1161            InputStream cis = null;
1162            OutputStream fos = null;
1163            long before = System.currentTimeMillis();                        
1164            try {
1165                fis = new FileInputStream(inFile);
1166                cis = new CipherInputStream(fis, decrypt);
1167                fos = new FileOutputStream(outFile);
1168                byte[] buffer = new byte[4096];
1169                loop:
1170                for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1171                    read = cis.read(buffer);
1172                    if (read == -1) {
1173                        if (k != 1) {
1174                            System.err.print('.');
1175                            for (int l = 0; l < (60 - k); l++) {
1176                                System.err.print(' ');
1177                            }
1178                        }
1179                        System.err.println("[" + i + "]");
1180                        System.err.println();
1181                        break loop;
1182                    }
1183                    fos.write(buffer, 0, (int) read);
1184                    i += read; 
1185                    if (i > j) {
1186                        if (k == 60) {
1187                            System.err.println('.' + "[" + i  + "]");
1188                            k = 1;
1189                        } else {
1190                            System.err.print('.');
1191                            k++;
1192                        }
1193                        j += 1024 * 100;
1194                    }
1195                }
1196                
1197            } finally {
1198                if (cis != null) {
1199                    try {
1200                        cis.close();
1201                    } finally {
1202                        if (fos != null) {
1203                            fos.close();
1204                        }
1205                    }
1206                } else if (fis != null) {
1207                    fis.close();
1208                }
1209            }
1210            long after = System.currentTimeMillis();
1211            System.err.print("Time to decrypt the whole file: ");
1212            System.err.println((after - before) + "ms");        
1213        }
1214        
1215        /**
1216         * Signs the "inFile" to the "sigFile" with the "keyFile".
1217         *
1218         * @throws Exception if something goes wrong.
1219         */    
1220        private void sign() throws Exception {
1221            if (inFile == null) {
1222                throw new Exception("You have to specify a MessageInputFile.");
1223            }
1224            if (sigFile == null) {
1225                throw new Exception("You have to specify a SignatureOutputFile.");
1226            }        
1227            
1228            header();
1229            System.err.println("Message File: " + inFile);
1230            System.err.println("Signature File: " + sigFile);
1231            System.err.println();
1232            
1233            RSAPrivateCrtKey privateCrtKey = 
1234            (RSAPrivateCrtKey) readKeyPair().getPrivate();
1235            System.err.println();
1236            Signature signer = 
1237            Signature.getInstance("RIPEMD160WithISO9796-1AndRSA", "JHBCI");
1238            signer.initSign(privateCrtKey);
1239            
1240            InputStream fin = null;
1241            long before = System.currentTimeMillis();
1242            try {
1243                fin = new FileInputStream(inFile);
1244                byte[] buffer = new byte[4096];
1245                loop:
1246                for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1247                    read = fin.read(buffer);
1248                    if (read == -1) {
1249                        if (k != 1) {
1250                            System.err.print('.');
1251                            for (int l = 0; l < (60 - k); l++) {
1252                                System.err.print(' ');
1253                            }
1254                        }
1255                        System.err.println("[" + i + "]");
1256                        System.err.println();
1257                        break loop;
1258                    }
1259                    signer.update(buffer, 0, (int) read);
1260                    i += read; 
1261                    if (i > j) {
1262                        if (k == 60) {
1263                            System.err.println('.' + "[" + i  + "]");
1264                            k = 1;
1265                        } else {
1266                            System.err.print('.');
1267                            k++;
1268                        }
1269                        j += 1024 * 100;
1270                    }
1271                }
1272            } finally {
1273                if (fin != null) {
1274                    fin.close();
1275                }
1276            }
1277            
1278            byte[] signature = null;
1279            OutputStream fos = null;
1280            try {
1281                fos = new FileOutputStream(sigFile);
1282                signature = signer.sign();
1283                fos.write(signature);
1284            } finally {
1285                if (fos != null) {
1286                    fos.close();
1287                }
1288            }
1289            
1290            System.err.println("Signature:");
1291            System.err.println("");
1292            System.err.println(toHex(signature));
1293            System.err.println();
1294            
1295            System.err.println("Signature successfully created.");
1296            System.err.println("");
1297    
1298            long after = System.currentTimeMillis();
1299            System.err.print("Time to sign the whole file: ");
1300            System.err.println((after - before) + "ms");        
1301        }
1302        
1303        /**
1304         * Verifies the "inFile" to with the "sigFile" and the "pubKeyFile".
1305         *
1306         * @throws Exception if something goes wrong.
1307         */    
1308        private void verify() throws Exception {
1309            if (inFile == null) {
1310                throw new Exception("You have to specify a MessageInputFile.");
1311            }
1312            if (sigFile == null) {
1313                throw new Exception("You have to specify a SignatureInputFile.");
1314            } 
1315            
1316            header();
1317            System.err.println("Message File: " + inFile);
1318            System.err.println("Signature File: " + sigFile);
1319            
1320            RSAPublicKey publicKey = readPublicKey();
1321            System.err.println();
1322            Signature verifier = 
1323            Signature.getInstance("RIPEMD160WithISO9796-1AndRSA", "JHBCI");
1324            verifier.initVerify(publicKey); 
1325            
1326            InputStream fin = null;
1327            long before = System.currentTimeMillis();
1328            try {
1329                fin = new FileInputStream(inFile);
1330                byte[] buffer = new byte[4096];
1331                loop:
1332                for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1333                    read = fin.read(buffer);
1334                    if (read == -1) {
1335                        if (k != 1) {
1336                            System.err.print('.');
1337                            for (int l = 0; l < (60 - k); l++) {
1338                                System.err.print(' ');
1339                            }
1340                        }
1341                        System.err.println("[" + i + "]");
1342                        System.err.println();
1343                        break loop;
1344                    }
1345                    verifier.update(buffer, 0, (int) read);
1346                    i += read; 
1347                    if (i > j) {
1348                        if (k == 60) {
1349                            System.err.println('.' + "[" + i  + "]");
1350                            k = 1;
1351                        } else {
1352                            System.err.print('.');
1353                            k++;
1354                        }
1355                        j += 1024 * 100;
1356                    }
1357                }
1358            } finally {
1359                if (fin != null) {
1360                    fin.close();
1361                }
1362            }        
1363            
1364            InputStream sfin = null;
1365            try {
1366                sfin = new FileInputStream(sigFile);
1367                byte[] buffer = null;
1368                byte[] signature = null;
1369                byte[] temp = null;
1370                loop2:
1371                for(int read = 0; true;) {
1372                    buffer = new byte[4096];
1373                    read = sfin.read(buffer);
1374                    if (read == -1) {
1375                        break;
1376                    }
1377                    if (signature == null) {
1378                        signature = new byte[read];
1379                        System.arraycopy(buffer, 0, signature, 0, read);
1380                    } else {
1381                        temp = signature;
1382                        signature = new byte[temp.length + read];
1383                        System.arraycopy(temp, 0, signature, 0, temp.length);
1384                        System.arraycopy(buffer, 0, signature, temp.length, read);
1385                        temp = null;
1386                    }
1387                }
1388    
1389                System.err.println("Signature:");
1390                System.err.println("");
1391                System.err.println(toHex(signature));
1392                System.err.println();        
1393                              
1394                boolean verified = verifier.verify(signature);
1395                if (verified) {
1396                    System.err.println("Signature successfully verified.");
1397                } else {
1398                    System.err.println("Signature rejected.");
1399                }
1400          
1401                long after = System.currentTimeMillis();
1402                System.err.println();
1403                System.err.print("Time to verify the whole file: ");
1404                System.err.println((after - before) + "ms");              
1405            } finally {
1406                if (sfin != null) {
1407                    fin.close();
1408                }
1409            }
1410        }
1411        
1412        /**
1413         * Digest the "inFile" to "digestFile".
1414         *
1415         * @throws Exception if something goes wrong.
1416         */    
1417        private void digest() throws Exception {
1418            if (inFile == null) {
1419                throw new Exception("You have to specify a MessageInputFile.");
1420            }
1421            if (digestFile == null) {
1422                throw new Exception("You have to specify a DigestOutputFile.");
1423            }
1424            
1425            header();
1426            System.err.println("Message File: " + inFile);
1427            System.err.println("Digest File: " + digestFile);
1428            System.err.println();
1429            
1430            MessageDigest digest = MessageDigest.getInstance("RIPEMD160", "JHBCI");
1431            InputStream fin = null;
1432            try {
1433                fin = new FileInputStream(inFile);
1434                byte[] buffer = new byte[4096];
1435                loop:
1436                for(long read = 0, i = 0, j = 1024 * 100, k = 1; true;) {
1437                    read = fin.read(buffer);
1438                    if (read == -1) {
1439                        if (k != 1) {
1440                            System.err.print('.');
1441                            for (int l = 0; l < (60 - k); l++) {
1442                                System.err.print(' ');
1443                            }
1444                        }
1445                        System.err.println("[" + i + "]");
1446                        System.err.println();
1447                        break loop;
1448                    }
1449                    digest.update(buffer, 0, (int) read);
1450                    i += read; 
1451                    if (i > j) {
1452                        if (k == 60) {
1453                            System.err.println('.' + "[" + i  + "]");
1454                            k = 1;
1455                        } else {
1456                            System.err.print('.');
1457                            k++;
1458                        }
1459                        j += 1024 * 100;
1460                    }
1461                }
1462            } finally {
1463                if (fin != null) {
1464                    fin.close();
1465                }
1466            }        
1467            
1468            byte[] messageDigest = digest.digest();
1469            
1470            OutputStream fos = null;
1471            PrintWriter pw = null;
1472            try {
1473                fos = new FileOutputStream(digestFile);
1474                pw = new PrintWriter(fos);
1475                System.err.println("Signature RIPEMD160:");
1476                System.err.println();
1477                System.err.println(toHex(messageDigest));
1478                pw.println(toHex(messageDigest));
1479            } finally {
1480                if (pw != null) {
1481                    pw.close();
1482                } else if( fos != null) {
1483                    fos.close();
1484                }
1485            }        
1486        }
1487        
1488        /**
1489         * Prints the header info of this tool.
1490         */
1491        private void header() {
1492            if (headerPrinted) {
1493                return ;
1494            } else {
1495                headerPrinted = true;
1496            }
1497            
1498            //Header
1499            System.err.println();
1500            System.err.print("CryptoTool v" + version + " Copyright (C) ");
1501            System.err.print("2001, 2002 ");
1502            System.err.print("Uwe Guenther <uwe@cscc.de> ");
1503            System.err.println();
1504            System.err.print("All Rights Reserved. ");
1505            System.err.print("(build 0.0.6-b72, 10/04/2003 09:23 PM)");
1506            System.err.println();    
1507            System.err.println();
1508        }
1509        
1510        /**
1511         * Prints the usage of this tool.
1512         */
1513        private void usage() {
1514            //header
1515            header();
1516            System.err.print("CryptoTool Usage:");
1517            System.err.println();
1518            System.err.println();
1519    
1520            //help
1521            System.err.print("-help     "); 
1522            System.err.print("Print out this usage message. ");
1523            System.err.println();
1524            System.err.println();        
1525            
1526            //genkey
1527            System.err.print("-genkey   "); 
1528            System.err.print("[-keysize <KeySize>] ");
1529            System.err.print("[-keyfile <KeyOutputFile>] ");
1530            System.err.println();
1531            System.err.print("          ");
1532            System.err.print("[-keypass <password>] ");
1533            System.err.println();
1534            System.err.print("          ");        
1535            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1536            System.err.println();
1537            System.err.println();
1538    
1539            //showkey
1540            System.err.print("-showkey  ");
1541            System.err.print("[-hex | -dec] ");
1542            System.err.print("[-keyfile <KeyInputFile>] ");
1543            System.err.println();
1544            System.err.print("          ");
1545            System.err.print("[-keypass <password>] ");
1546            System.err.println();
1547            System.err.print("          ");                
1548            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1549            System.err.println();
1550            System.err.println();
1551            
1552            //exportkey
1553            System.err.print("-export   "); 
1554            System.err.print("[-keyfile <KeyInputFile>] [-pubkey <PublicKeyOutputFile]");
1555            System.err.println();
1556            System.err.print("          ");
1557            System.err.print("[-keypass <password>] ");
1558            System.err.println();
1559            System.err.print("          ");                
1560            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1561            System.err.println();
1562            System.err.println();
1563            
1564            //showpubkey
1565            System.err.print("-showpub  ");
1566            System.err.print("[-hex | -dec] ");
1567            System.err.print("[-pubkey <PublicKeyInputFile>] ");
1568            System.err.println();
1569            System.err.print("          ");
1570            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1571            System.err.println();
1572            System.err.println();        
1573                    
1574            //encrypt
1575            System.err.print("-encrypt  ");
1576            System.err.print("[-in <PlainTextInputFile>] ");
1577            System.err.print("[-out <CipherTextOutputFile>] ");
1578            System.err.println();
1579            System.err.print("          ");
1580            System.err.print("[-pubkey <PublicKeyInputFile>] ");
1581            System.err.println();
1582            System.err.print("          ");        
1583            System.err.print("[-alg <DES1Key|DESede2Key|DESede3Key>] ");        
1584            System.err.println();
1585            System.err.print("          ");
1586            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");
1587            System.err.println();
1588            System.err.println();
1589            
1590            //decrypt
1591            System.err.print("-decrypt  ");
1592            System.err.print("[-in <CipherTextInputFile>] ");
1593            System.err.print("[-out <PlainTextOutputFile>] ");
1594            System.err.println();
1595            System.err.print("          ");
1596            System.err.print("[-keyfile <KeyInputFile>] ");
1597            System.err.print("[-keypass <password>] ");
1598            System.err.println();
1599            System.err.print("          ");
1600            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");
1601            System.err.println();
1602            System.err.println();
1603            
1604            //sign
1605            System.err.print("-sign     ");
1606            System.err.print("[-in <MessageInputFile>] ");
1607            System.err.print("[-sigfile <SignatureOutputFile>] ");
1608            System.err.println();
1609            System.err.print("          ");
1610            System.err.print("[-keyfile <KeyInputFile>] ");
1611            System.err.print("[-keypass <password>] ");        
1612            System.err.println();
1613            System.err.print("          ");
1614            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1615            System.err.println();
1616            System.err.println();        
1617            
1618            //verify
1619            System.err.print("-verify   ");
1620            System.err.print("[-in <MessageInputFile>] ");
1621            System.err.print("[-sigfile <SignatureInputFile>] ");
1622            System.err.println();
1623            System.err.print("          ");
1624            System.err.print("[-pubkey <PublicKeyInputFile>] ");
1625            System.err.println();
1626            System.err.print("          ");
1627            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1628            System.err.println();
1629            System.err.println();        
1630            
1631            //disgest
1632            System.err.print("-digest   ");
1633            System.err.print("[-in <MessageInputFile>] ");
1634            System.err.print("[-disgestfile <DigestOutputFile>] ");
1635            System.err.println();
1636            System.err.print("          ");
1637            System.err.print("[-logging <off|severe|warning|info|fine|finer|finest|all>] ");        
1638            System.err.println();
1639            System.err.println();
1640            
1641            //Finish, we lose ;-)
1642            System.exit(1);
1643        }
1644    }